import { assert, JsonAsset } from "cc";
import { app } from "../App";
import { IBaseBehavior } from "./base/IBaseBehavior";
import { IBehaviorTree } from "./base/IBehaviorTree";
import { BT_Type } from "./BTDefine";
import { BaseBehavior } from "./impl/BaseBehavior";
import { BehaviorTree } from "./impl/BehaviorTree";
import { Composite } from "./impl/composite/Composite";
import { Decorator } from "./impl/decorator/Decorator";

export interface BehaviorData {
    id: string;
    name: string;
    root?: boolean;
    children?: string[];
}

export class BTFactory {
    /****
        local treeData ={ 
            dataArr: [
                {
                    id = "1001",
                    name = "Sequence",
                    children = {"1002", "1004"}
                },
                {
                    id = "1002",
                    name = "TestDecorator",
                    child = "1003"
                },
                {
                    id = "1003",
                    name = "Test2Action"
                },
                {
                    id = "1004",
                    name = "Test3Action"
                }
            ]
        }
    
     */
    /**
     * 
     * @param json 
     * @param blackboard 
     * @returns 
     */
    static createWithJsonPath(jsonPath: string, blackboard?: any): Promise<IBehaviorTree> {

        return new Promise((resolve, reject) => {
            app.res.loadASync(jsonPath, JsonAsset).then((res: JsonAsset) => {
                if (res) {
                    const jsonData: object = res.json!;

                    let ret = this.createWithJsonObject(jsonData);

                    resolve(ret);

                } else {
                    resolve(null);
                }

            });

        });

    }

    static createWithJsonString(jsonStr: string, blackboard?: any): IBehaviorTree {
        let jsonObject = JSON.parse(jsonStr);

        return this.createWithJsonObject(jsonObject, blackboard);
    }

    static createWithJsonObject(jsonObject: object, blackboard?: any): IBehaviorTree {
        let rootNode = null;

        for (let i = 0; i < jsonObject['dataArr'].length; i++) {
            let id = jsonObject['dataArr'][i]['id'];
            let name = jsonObject['dataArr'][i]['name'];
            let node = BTFactory.getNode(name);
            BTFactory.registerNode(id, node);

            if (jsonObject['dataArr'][i]['root']) {
                rootNode = node;
            }
        }

        for (let i = 0; i < jsonObject['dataArr'].length; i++) {
            let id = jsonObject['dataArr'][i]['id'];
            let name = jsonObject['dataArr'][i]['name'];
            let node = BTFactory.getNode(id);

            if (node.getType() === BT_Type.TYPE_COMPOSITE) {
                let compositeNode = <Composite>node;
                let children = jsonObject['dataArr'][i]['children'];
                for (let j = 0; j < children.length; j++) {
                    let childid = children[j];
                    let child = BTFactory.getNode(childid);
                    compositeNode.addChild(child);
                }
            } else if (node.getType() === BT_Type.TYPE_DECORATOR) {
                let decoratorNode = <Decorator>node;
                let childid = jsonObject['dataArr'][i]['child'];
                decoratorNode.setChild(BTFactory.getNode(childid));
            }
        }


        let ret = new BehaviorTree;
        ret.setRoot(rootNode);
        ret.setBlackboard(blackboard);

        return ret;
    }

    static createWithData(dataArr: Array<BehaviorData>, blackboard?: any): IBehaviorTree {
        let rootNode = null;

        for (let i = 0; i < dataArr.length; i++) {
            let data = dataArr[i];
            let node = BTFactory.getNode(data.name);
            BTFactory.registerNode(data.id, node);

            if (data.root) {
                rootNode = node;
            }
        }

        for (let i = 0; i < dataArr.length; i++) {
            let data = dataArr[i];
            let node = BTFactory.getNode(data.id);
            if (node.getType() === BT_Type.TYPE_COMPOSITE) {
                let compositeNode = <Composite>node;
                let children = data.children;
                for (let j = 0; j < children.length; j++) {
                    let childId = children[j];
                    let child = BTFactory.getNode(childId);
                    compositeNode.addChild(child);
                }
            } else if (node.getType() === BT_Type.TYPE_DECORATOR) {
                let decoratorNode = <Decorator>node;
                let childId = data.children[0];
                decoratorNode.setChild(BTFactory.getNode(childId));
            }
        }

        let ret = new BehaviorTree;
        ret.setRoot(rootNode);
        ret.setBlackboard(blackboard);

        return ret;
    }

    static creatWithRoot(rootNode: IBaseBehavior, blackboard?: any): IBehaviorTree {
        let ret = new BehaviorTree;
        ret.setRoot(rootNode);
        ret.setBlackboard(blackboard);
        return ret;
    }


    static registedBTNode: Map<string, IBaseBehavior> = new Map();

    static registerNode(name: string, node: IBaseBehavior) {
        this.registedBTNode.set(name, node);
    }

    static getNode(name: string | IBaseBehavior): IBaseBehavior {
        if (typeof name === "string") {
            let node = this.registedBTNode.get(name);
            if (node) {
                return node;
            } else {
                assert(false, '没有找到这个行为类：' + name);
            }
        } else if (name instanceof BaseBehavior) {
            return name;
        }

    }

}